package simq

import (
	"context"
	"github.com/rivo/tview"
	"log"
)

type config struct {
	LocalAddress  string
	RemoteAddress string
	DataRate      float64
	PacketSize    int
	Data          []byte
	HeaderSize    int
}

type testInfoUI struct {
	ctx      context.Context
	cancel   context.CancelFunc
	app      *tview.Application
	panel    *tview.Flex
	testType *tview.TextView

	rxType       *tview.TableCell
	rxReasonCode *tview.TableCell
	rxFixHeader  *tview.TableCell
	rxVarHeader  *tview.TableCell
	rxLoad       *tview.TableCell
	rxData       *tview.TableCell

	sentPackets     uint64
	receivedPackets uint64
	sizeErrors      uint64
	dataErrors      uint64
	sentBytes       int64
	receivedBytes   int64
	lastTS          int64
}

// createCommandList 左边commands面板
func createCommandList(app *tview.Application, pages *tview.Pages, infoUI *testInfoUI, conf *config) (commandList *tview.List) {
	///// Commands /////
	commandList = tview.NewList()
	commandList.SetBorder(true).SetTitle("Commands")
	commandList.ShowSecondaryText(false)

	commandList.AddItem("Connect", "", '1', connect(pages, infoUI, conf))
	commandList.AddItem("Connack", "", '2', connack(pages, infoUI, conf))
	commandList.AddItem("Publish", "", '3', publish(pages, infoUI, conf))
	commandList.AddItem("Puback", "", '4', puback(pages, infoUI, conf))
	commandList.AddItem("Pubrec", "", '5', pubrec(pages, infoUI, conf))
	commandList.AddItem("Pubrel", "", '6', pubrel(pages, infoUI, conf))
	commandList.AddItem("Pubcomp", "", '7', pubcomp(pages, infoUI, conf))
	commandList.AddItem("Subscribe", "", '8', subscribe(pages, infoUI, conf))
	commandList.AddItem("Suback", "", '9', suback(pages, infoUI, conf))
	commandList.AddItem("Unsubscribe", "", 'a', unsubscribe(pages, infoUI, conf))
	commandList.AddItem("Unsuback", "", 'b', unsuback(pages, infoUI, conf))
	commandList.AddItem("Pingreq", "", 'c', pingreq(pages, infoUI, conf))
	commandList.AddItem("Pingresp", "", 'd', pingresp(pages, infoUI, conf))
	commandList.AddItem("Disconnect", "", 'e', disconnect(pages, infoUI, conf))
	commandList.AddItem("Auth", "", 'f', auth(pages, infoUI, conf))

	commandList.AddItem("QUIT", "", 'q', func() {
		app.Stop()
	})
	return commandList
}

// createInfoPanel 创建右边显示面板
func createInfoPanel(app *tview.Application) (infoUI *testInfoUI) {
	///// Info /////
	infoPanel := tview.NewFlex().SetDirection(tview.FlexRow)

	infoUI = &testInfoUI{}
	infoUI.app = app
	infoUI.panel = infoPanel

	infoUI.testType = tview.NewTextView()
	infoUI.testType.SetBorder(true)
	infoUI.testType.SetText("Package")
	infoUI.testType.SetTextAlign(tview.AlignCenter)
	infoPanel.AddItem(infoUI.testType, 3, 1, false)

	txInfo := tview.NewTable()
	txInfo.SetBorder(true).SetTitle("Encode")

	txInfo.SetCellSimple(0, 0, "Message Type:")
	txInfo.GetCell(0, 0).SetAlign(tview.AlignRight)
	infoUI.rxType = tview.NewTableCell("0")
	txInfo.SetCell(0, 1, infoUI.rxType)

	txInfo.SetCellSimple(0, 0, "Reason Code:")
	txInfo.GetCell(0, 0).SetAlign(tview.AlignRight)
	infoUI.rxReasonCode = tview.NewTableCell("0")
	txInfo.SetCell(0, 1, infoUI.rxReasonCode)

	txInfo.SetCellSimple(1, 0, "Fixed header:")
	txInfo.GetCell(1, 0).SetAlign(tview.AlignRight)
	infoUI.rxFixHeader = tview.NewTableCell("0")
	txInfo.SetCell(1, 1, infoUI.rxFixHeader)

	txInfo.SetCellSimple(2, 0, "Variable header:")
	txInfo.GetCell(2, 0).SetAlign(tview.AlignRight)
	infoUI.rxVarHeader = tview.NewTableCell("0")
	txInfo.SetCell(2, 1, infoUI.rxVarHeader)

	txInfo.SetCellSimple(3, 0, "Load:")
	txInfo.GetCell(3, 0).SetAlign(tview.AlignRight)
	infoUI.rxLoad = tview.NewTableCell("0")
	txInfo.SetCell(3, 1, infoUI.rxLoad)

	txInfo.SetCellSimple(4, 0, "Data:")
	txInfo.GetCell(4, 0).SetAlign(tview.AlignRight)
	infoUI.rxData = tview.NewTableCell("0")
	txInfo.SetCell(4, 1, infoUI.rxData)

	rxInfo := tview.NewTable()
	rxInfo.SetBorder(true).SetTitle("Decode")

	infoInnerPanel := tview.NewFlex().SetDirection(tview.FlexColumn).
		AddItem(txInfo, 0, 1, false).
		AddItem(rxInfo, 0, 1, false)

	infoPanel.AddItem(infoInnerPanel, 0, 1, false)

	return infoUI
}
func createTextViewPanel(app *tview.Application, name string) (panel *tview.TextView) {
	panel = tview.NewTextView()
	panel.SetBorder(true).SetTitle(name)
	panel.SetChangedFunc(func() {
		app.Draw()
	})
	return panel
}

func createOutputPanel(app *tview.Application, infoPanel *tview.Flex, logPanel *tview.TextView) (outputPanel *tview.Flex) {
	outputPanel = tview.NewFlex().SetDirection(tview.FlexRow).
		AddItem(infoPanel, 10, 1, true).
		AddItem(logPanel, 0, 1, false)
	return outputPanel
}
func createMainLayout(commandList tview.Primitive, outputPanel tview.Primitive) (layout *tview.Flex) {
	///// Main Layout /////
	mainLayout := tview.NewFlex().SetDirection(tview.FlexColumn).
		AddItem(commandList, 30, 1, true).
		AddItem(outputPanel, 0, 4, false)

	info := tview.NewTextView()
	info.SetBorder(true)
	info.SetText("SIMQ Packet Protocol Tester v1.0 - Copyright 2021 Andrew SaltIce <2018214546@qq.com>")
	info.SetTextAlign(tview.AlignCenter)

	layout = tview.NewFlex().SetDirection(tview.FlexRow).
		AddItem(mainLayout, 0, 20, true).
		AddItem(info, 3, 1, false)

	return layout
}
func createSIMQApplication() (app *tview.Application) {
	app = tview.NewApplication()
	pages := tview.NewPages()

	infoUI := createInfoPanel(app)
	logPanel := createTextViewPanel(app, "Log")
	outputPanel := createOutputPanel(app, infoUI.panel, logPanel)

	log.SetOutput(logPanel)

	//conf := loadConfig()
	commandList := createCommandList(app, pages, infoUI, &config{})
	layout := createMainLayout(commandList, outputPanel)
	pages.AddPage("main", layout, true, true)

	app.SetRoot(pages, true)

	return app
}
func SIMQApp() {
	app := createSIMQApplication()

	if err := app.Run(); err != nil {
		panic(err)
	}
}
